using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Serialization;
using UnityEngine.UI.Extensions.EasingCore;

namespace UnityEngine.UI.Extensions
{
    /// <summary>
    /// ScrollView 外部使用
    /// </summary>
    public class UIScrollViewRect : FancyScrollRect<UICellData, UIContextRect>
    {
        [SerializeField]
        private FancyScroller m_Scroller = default;
        [SerializeField]
        private GameObject m_CellPrefab = default;
        [SerializeField]
        private float m_CellSize = 100f;

        public FancyScroller Scroller
        {
            get
            {
                return m_Scroller;
            }
            private set
            {
                m_Scroller = value;
            }
        }

        /// <summary>
        /// 目标是ItemPrefab
        /// </summary>
        public override GameObject CellPrefab
        {
            get
            {
                return m_CellPrefab;
            }
        }

        /// <summary>
        /// Item大小
        /// </summary>
        public override float CellSize
        {
            get
            {
                return m_CellSize;
            }
        }

        /// <summary>
        /// 数据大小。
        /// </summary>
        public int DataCount
        {
            get
            {
                return ItemsSource.Count;
            }
        }

        /// <summary>
        /// 顶部扩展位置。
        /// </summary>
        public float PaddingTop
        {
            get
            {
                return paddingHead;
            }
            set
            {
                paddingHead = value;
                Relayout();
            }
        }

        /// <summary>
        /// 底部扩展位置。
        /// </summary>
        public float PaddingBottom
        {
            get
            {
                return paddingTail;
            }
            set
            {
                paddingTail = value;
                Relayout();
            }
        }

        /// <summary>
        /// Item直接间隔。
        /// </summary>
        public float Spacing
        {
            get
            {
                return spacing;
            }
            set
            {
                spacing = value;
                Relayout();
            }
        }

        private void Awake()
        {
            if (!Scroller)
            {
                Scroller = GetComponent<FancyScroller>();
            }
        }

        /// <summary>
        /// 更新数据。
        /// </summary>
        /// <param name="count"></param>
        public void UpdateData(int count)
        {
            IList<UICellData> list = new List<UICellData>();

            for (int i = 0; i < count; i++)
            {
                list.Add(new UICellData(i));
            }

            UpdateData(list);
        }

        /// <summary>
        /// 更新数据。
        /// </summary>
        /// <param name="items"></param>
        public void UpdateData(IList<UICellData> items)
        {
            UpdateContents(items);
            Scroller.SetTotalCount(items.Count);
        }

        /// <summary>
        /// 滚动到指定位置，一般运行时带动画滚动到指定Index。
        /// </summary>
        /// <param name="index"></param>
        /// <param name="duration"></param>
        /// <param name="easing"></param>
        /// <param name="alignment"></param>
        public void ScrollTo(int index, float duration, Ease easing, Alignment alignment = Alignment.Middle)
        {
            UpdateSelectionByScroll(index, duration, easing, alignment);
        }

        /// <summary>
        /// 滚动到下一个Item。
        /// </summary>
        public void ScrollToNext()
        {
            UpdateSelectionByScroll(Context.SelectedIndex + 1, 0.35f, Ease.OutCubic);
        }

        /// <summary>
        /// 滚动到下一个Item。
        /// </summary>
        /// <param name="duration"></param>
        /// <param name="easing"></param>
        /// <param name="alignment"></param>
        public void ScrollToNext(float duration, Ease easing, Alignment alignment = Alignment.Middle)
        {
            UpdateSelectionByScroll(Context.SelectedIndex + 1, duration, easing, alignment);
        }

        public void ScrollToPre()
        {
            UpdateSelectionByScroll(Context.SelectedIndex - 1, 0.35f, Ease.OutCubic);
        }

        /// <summary>
        /// 滚动到上一页。
        /// </summary>
        /// <param name="duration"></param>
        /// <param name="easing"></param>
        /// <param name="alignment"></param>
        public void ScrollToPre(float duration, Ease easing, Alignment alignment = Alignment.Middle)
        {
            UpdateSelectionByScroll(Context.SelectedIndex - 1, duration, easing, alignment);
        }

        /// <summary>
        /// 跳转到指定位置，一般初始化时不带动画跳转到指定Index。
        /// </summary>
        /// <param name="index"></param>
        /// <param name="alignment"></param>
        public void JumpTo(int index, Alignment alignment = Alignment.Middle)
        {
            UpdateSelectionByJump(index, alignment);
        }

        /// <summary>
        /// 跳转到下一个Item。
        /// </summary>
        public void JumpToNext()
        {
            UpdateSelectionByJump(Context.SelectedIndex + 1);
        }
        
        /// <summary>
        /// 跳转到下一个Item。
        /// </summary>
        /// <param name="alignment"></param>
        public void JumpToNext(Alignment alignment = Alignment.Middle)
        {
            UpdateSelectionByJump(Context.SelectedIndex + 1, alignment);
        }

        /// <summary>
        /// 跳转到上一个Item。
        /// </summary>
        public void JumpToPre()
        {
            UpdateSelectionByJump(Context.SelectedIndex - 1);
        }

        /// <summary>
        /// 跳转到上一个Item。
        /// </summary>
        /// <param name="alignment"></param>
        public void JumpToPre(Alignment alignment = Alignment.Middle)
        {
            UpdateSelectionByJump(Context.SelectedIndex - 1, alignment);
        }

        /// <summary>
        /// 获取对其方式。
        /// </summary>
        /// <param name="alignment"></param>
        /// <returns></returns>
        private float GetAlignment(Alignment alignment)
        {
            switch (alignment)
            {
                case Alignment.Upper:
                    return 0.0f;

                case Alignment.Middle:
                    return 0.5f;

                case Alignment.Lower:
                    return 1.0f;

                default:
                    return GetAlignment(Alignment.Middle);
            }
        }
        
        /// <summary>
        /// 更新选择依靠滚动。
        /// </summary>
        /// <param name="index"></param>
        /// <param name="duration"></param>
        /// <param name="easing"></param>
        /// <param name="alignment"></param>
        private void UpdateSelectionByScroll(int index, float duration, Ease easing, Alignment alignment = Alignment.Middle)
        {
            if (CanSelection(index))
            {
                ScrollTo(index, duration, easing, GetAlignment(alignment));    
            }
        }

        /// <summary>
        /// 更新选择依靠跳转。
        /// </summary>
        /// <param name="index"></param>
        /// <param name="alignment"></param>
        private void UpdateSelectionByJump(int index, Alignment alignment = Alignment.Middle)
        {
            if (CanSelection(index))
            {
                JumpTo(index, GetAlignment(alignment));    
            }
        }

        /// <summary>
        /// 是否可以选择。
        /// </summary>
        /// <param name="index"></param>
        /// <returns></returns>
        private bool CanSelection(int index)
        {
            if (index < 0 || index >= ItemsSource.Count || index == Context.SelectedIndex)
            {
                return false;
            }

            Context.SelectedIndex = index;
            Refresh();
            return true;
        }
    }
}